package com.zhl.study.cyclicBarrier;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CyclicBarrier;

/**
 * @description CyclicBarrier 是一个同步辅助工具，允许一组线程相互等待，直到到达某个公共的屏障点。它可以被重复使用。
 * 它与 CountDownLatch 有什么区别？
 *      CountDownLatch 是一次性的，计数器到达零后不能重置。
 *      CyclicBarrier 是可循环使用的，屏障被突破后可以重新使用。
 * CyclicBarrier的常用方法:
 *      CyclicBarrier(int parties)
 *          创建一个新的CyclicBarrier实例,需要指定参与的线程数量。
 *      CyclicBarrier(int parties, Runnable barrierAction)
 *          创建一个新的CyclicBarrier实例,并指定当所有线程都到达屏障点后,要执行的动作。
 *      int await() throws InterruptedException, BrokenBarrierException
 *          当前线程在此处被阻塞,直到所有线程都达到了屏障点后才能继续执行。
 *      int getNumberWaiting()
 *          返回当前正在等待的参与线程数。
 *      int getParties()
 *          返回需要在屏障处等待的参与线程数。
 *      boolean isBroken()
 *          查询此屏障是否处于损坏状态。
 *      void reset()
 *          将屏障重置为其初始状态,使其可用于下一次使用。
 * @Author: z156940l@outlook.com
 * @className CyclicBarrierDemo
 * @Date: 2024/5/22 19:42
 */
@Slf4j
public class CyclicBarrierDemo {

    /**
     * 并行计算
     * 在并行计算中,可以使用CyclicBarrier来同步多个线程在每个阶段的开始和结束时。示例代码:
     */
    public void parallelComputing(){
        int numThreads = 5;
        CyclicBarrier barrier = new CyclicBarrier(numThreads);
        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                try {
                    // 执行计算任务
                    log.info("{} is working...,time:{}", Thread.currentThread().getName(), System.currentTimeMillis());
                    barrier.await(); // 等待其他线程完成当前阶段

                    // 执行另一个计算任务
                    log.info("{} is working again...,time:{}", Thread.currentThread().getName(), System.currentTimeMillis());
                    barrier.await(); // 等待其他线程完成下一阶段
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    /**
     * 多线程协作
     * 当多个线程需要相互协作完成一项任务时,可以使用CyclicBarrier来同步各个线程的执行步骤。示例代码:
     */
    public void multiThreadedCollaboration(){
        int numThreads = 13;
        CyclicBarrier barrier = new CyclicBarrier(numThreads, () -> log.info("All threads are ready!"));

        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                try {
                    // 执行任务的第一步
                    log.info("Thread {} is executing step 1...,time:{}", Thread.currentThread().getName(), System.currentTimeMillis());
                    barrier.await(); // 等待其他线程完成第一步

                    // 执行任务的第二步
                    log.info("Thread {} is executing step 2...,time:{}", Thread.currentThread().getName(), System.currentTimeMillis());
                    barrier.await(); // 等待其他线程完成第二步
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    /**
     * 分阶段任务
     * 如果一个任务可以分为多个阶段,每个阶段由多个线程并行执行,可以使用CyclicBarrier在阶段之间进行同步。示例代码:
     */
    public void stagedTasks(){
        int numThreads = 5;
        CyclicBarrier barrier = new CyclicBarrier(numThreads);
        for (int i = 0; i < numThreads; i++) {
            new Thread(() -> {
                try {
                    // 执行任务的第一阶段
                    log.info("Thread {} is executing phase 1...,time:{}", Thread.currentThread().getName(), System.currentTimeMillis());
                    barrier.await(); // 等待所有线程完成第一阶段

                    // 执行任务的第二阶段
                    log.info("Thread {} is is executing phase 2...,time:{}", Thread.currentThread().getName(), System.currentTimeMillis());
                    barrier.await(); // 等待所有线程完成第二阶段
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    /**
     * 健康检查
     * 在分布式系统中,可以使用CyclicBarrier来同步所有节点的健康检查操作。示例代码:
     */
    public void healthCheck(){
        int numNodes = 3;
        CyclicBarrier barrier = new CyclicBarrier(numNodes, () -> log.info("All nodes are healthy!"));
        for (int i = 0; i < numNodes; i++) {
            new Thread(() -> {
                try {
                    // 执行节点的健康检查
                    log.info("Thread {} is performing health check...,time:{}", Thread.currentThread().getName(), System.currentTimeMillis());
                    Thread.sleep(1000); // 模拟检查操作
                    barrier.await(); // 等待所有节点完成健康检查
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
